#include <memory>
#include "socket.hpp"
#include "cal.hpp"

using func_t = function<void(my_socket *)>; // 执行任务的方法

class tcp_server
{
public:
    tcp_server(uint16_t port, func_t f)
        : _port(port), _sv(new tcp_socket()), _func(f)
    {
        _sv->tcpserver_socket(port);
    }

    void thread_run(my_socket *socket) // 线程执行区域
    {
        while (true)
        {
            _func(socket);
            // socket->Close(); // 运行完毕就直接关闭accept返回的套接字描述符
        }
    }

    void loop()
    {
        while (1)
        {
            string client_ip;
            uint16_t client_port;
            my_socket *socket = _sv->Accept(client_ip, client_port); // 接收套接字
            cout << "获取新连接: ip= " << client_ip << " port= " << client_port << endl;

            // 创建线程执行任务
            // thread t(std::bind(&tcp_server::thread_run, this, placeholders::_1), socket);
            thread t(&tcp_server::thread_run, this, socket);
            t.detach(); // 线程分离
        }
    }

    ~tcp_server()
    {
        delete _sv;
    }

private:
    my_socket *_sv;
    uint16_t _port;
    func_t _func;
};

void deal(my_socket *socket) // 存的套接字描述符就是accept返回值
{
    string buffer;
    while (1)
    {
        // 1.数据读取
        string onerecv;
        socket->Recv(onerecv, 100); // 将每一次序列化的数据都读进buffer里
        buffer += onerecv;          // 将每次读取的数据都push进去

        string msg;
        string total_info;

        // 2.解包装(将所有读到的数据都解包，最后完成后一起再发送出去)
        while (Decode(buffer, msg)) // 此时buffer会存在残留数据
        {
            // 3.反序列化buffer,
            Request rq;
            rq.Deserialize(msg);

            // 4.数据读取完毕可以进行处理
            Cal c(rq);
            Response rsp = c.cal(); // 计算结果存到rsp里

            // 5.将处理结果返回给客户端(需要进行序列化和加包)
            string s;
            rsp.Serialize(s);
            Encode(s);
            total_info += s;
        }
        send(socket->Get_sockfd(), total_info.c_str(), total_info.size(), 0); // 任务发送给服务器
    }
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "格式错误\n正确格式:" << argv[0] << " port"
             << endl;
    }
    uint16_t port = atoi(argv[1]);

    unique_ptr<tcp_server> tsv = make_unique<tcp_server>(port, deal);
    tsv->loop(); // accept客户端套接字

    return 0;
}
